home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-05-11 | 15.0 KB | 767 lines | [TEXT/MMCC] |
- //==================================================================
- // MacMain.c <tur 01-May-94>
- //
- // A quickie Macintosh main program to be bolted onto
- // Chris Laurel's "wt" thingy...
- //
- // Comments, Bug Reports/Fixes, etc, to turly@isltd.insignia.com
- //
- //==================================================================
-
- #ifndef __QUICKDRAW__
- #include "LoadMacHeaders.h"
- #endif /* __QUICKDRAW__ */
-
- #include <stdio.h>
- #include <stdarg.h>
- #include <string.h>
- #if !(THINK_C || THINK_CPLUS)
- #include <Strings.h> /* p2cstr, etc. */
- #endif
- #include <AppleEvents.h>
- #include "DirScrnWrite.h"
- #include "Failure.h"
- #include "error.h"
- #include "framebuf.h"
- #include "graphics.h"
- #include "MacGame.h"
-
- #if applec || __ppcc
- #include <PLStringFuncs.h>
- #endif
-
-
- /**/
-
-
- #define kMinMem (640<<10) /* Absolute minimum memory required */
-
- enum {kTab = 9, kSpace = 20, kEsc = 27}; /* Hacky ASCII codes */
-
- enum {rMBarID = 128,
- rAppleMenuID = 128, rFileMenuID, rEditMenuID};
-
- enum {rAppleAbout = 1,
- rFileNewGame = 1, rFileDiv1, rFileShowFPS, rFileUseQD, rFilePause, rFileDiv2, rFileQuit};
-
- enum {rFatalErrorAlert = 32765,
- rAboutAlert = 32766,
- rBadStartAlert = 32767};
-
- enum {rWindowID = 128};
-
- enum {rUtilityStrs = 128,
- rStrPause = 1, rStrContinue, rDirWrite, rNoDirWrite};
-
-
- /**/
-
-
- static void doMenu(long mResult);
- pascal StringPtr PLstrcpy(StringPtr dst, StringPtr src);
- pascal StringPtr PLstrcat(StringPtr dst, StringPtr str2);
-
-
- /**/
-
-
- EventRecord gTheEvent;
- Boolean gDone = false;
- Boolean gUseQuickDraw = false;
- Boolean gPaused = false;
- Boolean gShowFPS = true;
- Boolean gGameOn = false;
- char gWorldFileName[256];
- Str15 gWTVersion = "\pUnknown";
-
- #if __ppcc
- QDGlobals qd;
- #endif
-
-
- /**/
-
-
- const unsigned char nullStr[1] = {0};
-
-
- /**/
-
-
- static WindowPtr gMainWindow;
- static int gYieldTime = 0;
- static SysEnvRec gTheSysEnv;
- static MenuHandle gAppleMenu, gFileMenu, gEditMenu;
- static Boolean gInBackground = false;
-
-
- /**/
-
-
- static int initPal(PaletteHandle pal)
- {
- return LoadPaletteFromFile(pal, nil); // pickup default palette
- }
-
-
- /**/
-
-
- static void showFailure(ConstStr255Param unixStr)
- {
- Str255 macStr;
- int i;
-
- // Disgusting hackery to convert LFs to CRs for the Mac error string.
-
- macStr[0] = unixStr[0];
-
- for (i = 1; i <= unixStr[0]; ++i)
- macStr[i] = (unixStr[i] == 10) ? 13 : unixStr[i];
-
- ParamText(macStr, nullStr, nullStr, nullStr);
- Alert(rFatalErrorAlert, nil);
- }
-
-
- /**/
-
-
- void fatal_error(char *fmt, ...)
- {
- va_list args;
- char buf[256];
-
- va_start(args, fmt);
- buf[0] = vsprintf(buf+1, fmt, args);
- va_end(args);
-
- showFailure((StringPtr)buf);
- ExitToShell();
- }
-
-
- /**/
-
-
- #ifndef __PLSTRINGFUNCS__
-
- // Grrr -- need to hack together my own versions of PLstrcpy and PLstrcat for THICK C and MWC/PPC!
-
- pascal StringPtr PLstrcpy(StringPtr str1, StringPtr str2)
- {
- unsigned char *cp = str1;
- unsigned len = *(unsigned char *)str2;
-
- // Need to copy length byte as well, remember...
-
- do {
- *cp++ = *str2++;
- } while (len--);
-
- return str1;
- }
-
-
- /**/
-
-
- pascal StringPtr PLstrcat(StringPtr str1, StringPtr str2)
- {
- unsigned char *cp = str1;
- unsigned len1 = *(unsigned char *)str1,
- len2 = *(unsigned char *)str2;
-
- if ((len1 + len2) >= 255) {
- DebugStr((unsigned char *)"\pString concatenation -- dest too big!");
- return 0;
- }
-
- cp += len1 + 1; // skip to end of str1
- *(unsigned char *)str1 += len2; // adjust length byte
- ++str2; // don't copy "str2" length byte
-
- while (len2--)
- *cp++ = *str2++;
-
- return str1;
- }
-
- #endif /* __PLSTRINGFUNCS__ */
-
-
- /**/
-
-
- #ifndef __STRINGS__
-
- char *p2cstr(StringPtr pStr)
- {
- unsigned len;
- char *cp;
-
- len = *(unsigned char *)pStr;
- cp = (char *)pStr;
-
- while (len--) {
- cp[0] = cp[1]; // slide chars backwards (over length byte)
- ++cp;
- }
-
- *cp = 0; // terminate C-string
-
- return (char *)pStr; // return now C-style string
- }
-
- StringPtr c2pstr(char *cStr)
- {
- unsigned char *cp;
- unsigned len, cStrLen;
-
- cStrLen = len = strlen(cStr);
-
- if (len > 255) // perhaps we should have a _DebugStr here...
- len = 255; // (don't overrun the max length)
-
- cp = (unsigned char *)cStr + len - 1;
-
- while (len--) {
- cp[1] = cp[0]; // slide chars forward (make room for length byte)
- --cp;
- }
-
- *cStr = cStrLen; // bung in length byte
-
- return (StringPtr)cStr; // return now-pascal style string
- }
-
- #endif /* __STRINGS__ */
-
-
- /**/
-
-
- static int PathNameFromDirID(int vRefNum, long dirID, Str255 fullPathName)
- {
- Str255 dirName;
- DirInfo dirInf;
- OSErr err;
-
- *fullPathName = 0;
-
- dirInf.ioNamePtr = dirName;
- dirInf.ioDrParID = dirID;
-
- do {
- dirInf.ioVRefNum = vRefNum;
- dirInf.ioFDirIndex = -1; // -1 means use ioDrDirID…
- dirInf.ioDrDirID = dirInf.ioDrParID;
-
- err = PBGetCatInfoSync((CInfoPBPtr)&dirInf);
-
- if (err == noErr) {
- dirName[++dirName[0]] = ':';
-
- if (dirName[0] + fullPathName[0] > 255)
- err = bdNamErr; // too big to eat!
- else {
- PLstrcat(dirName, fullPathName);
- PLstrcpy(fullPathName, dirName);
- }
- }
-
- } while (dirInf.ioDrDirID != fsRtDirID && err == noErr);
-
- return err;
-
- } // PathNameFromDirID
-
-
- /**/
-
-
- /* Standard AppleEvents stuff.
- ** We support only the required AppleEvents.
- ** We •really• support only the OpenDoc and Quit AppleEvents!
- */
- static OSErr AEGotRequiredParams(AppleEvent *aevt)
- {
- register OSErr err;
- Size actualSize;
- DescType typeCode;
-
- // see if we've got all the parameters...
-
- err = AEGetAttributePtr(aevt, keyMissedKeywordAttr, typeWildCard, &typeCode,
- NULL, 0, &actualSize);
-
- if (err == errAEDescNotFound) // No "missed keyword" attribute ==> got all required params
- err = noErr;
- else
- if (err == noErr) // "missed keyword" attribute exists ==> missed at least one
- err = errAEParamMissed;
-
- return err;
- }
-
-
- /**/
-
-
- /* AEOpenApp -- the “open application” AppleEvent.
- ** Return noErr UNLESS there are “missing parameters” (a good trick, since
- ** this AppleEvent doesn’t have any!)
- **
- */
- static pascal OSErr AEOpenApp(AppleEvent *request, AppleEvent *reply, long handlerRefCon)
- {
- return AEGotRequiredParams(request);
- }
-
-
- /**/
-
-
- /* AEOpenDocs
- ** Fetch the list of things to be opened.
- */
- static pascal OSErr AEOpenDocs(register AppleEvent *request, AppleEvent *reply, long ref)
- {
- return errAEEventNotHandled;
- }
-
-
- /**/
-
-
- /* AEPrintDocs -- we can’t print documents… */
- static pascal OSErr AEPrintDocs(AppleEvent *request, AppleEvent *reply, long ref)
- {
- return errAEEventNotHandled;
- }
-
-
- /**/
-
-
- static pascal OSErr AEQuitApp(AppleEvent *request, AppleEvent *reply, long ref)
- {
- register OSErr err;
-
- err = AEGotRequiredParams(request);
-
- if (err == noErr)
- doMenu((rFileMenuID << 16) | rFileQuit);
-
- return err;
- }
-
-
- /**/
-
-
- static void init(void)
- {
- int err;
- Handle mbh;
- WStateData **wHndl;
- StandardFileReply sfReply;
- Str255 titleStr;
- unsigned char **versRsrc;
-
- MaxApplZone(); /* so code segments load at top… */
-
- FlushEvents(everyEvent - diskMask, 0); /* so disks inserted while app starts */
- /* all work OK (no dead disks) */
- InitGraf(&qd.thePort); /* ritual incantation #2423: */
- InitFonts();
- InitWindows();
- InitMenus();
- TEInit();
- InitDialogs(nil);
- InitCursor();
-
- gShowFailProc = showFailure; // for failure purposes...
-
- /* Set up menus... */
- mbh = GetNewMBar(rMBarID);
- FailNil(mbh);
- SetMenuBar(mbh); // install the menubar!
-
- gAppleMenu = GetMHandle(rAppleMenuID); // add the DAs to the Apple menu
- FailNil(gAppleMenu);
- AddResMenu(gAppleMenu, 'DRVR');
-
- gFileMenu = GetMHandle(rFileMenuID);
- FailNil(gFileMenu);
- SetItemMark(gFileMenu, rFileUseQD, (gUseQuickDraw) ? checkMark : noMark);
- SetItemMark(gFileMenu, rFileShowFPS, (gShowFPS) ? checkMark : noMark);
-
- gEditMenu = GetMHandle(rEditMenuID);
- FailNil(gEditMenu);
-
- DrawMenuBar();
-
- /* Catch as many failures as possible now... */
-
- err = SysEnvirons(curSysEnvVers, &gTheSysEnv);
- if (err || !gTheSysEnv.hasColorQD || gTheSysEnv.systemVersion < 0x0700 ||
- ((long)GetApplLimit() - (long)ApplicZone()) < kMinMem) {
- StopAlert(rBadStartAlert, nil);
- ExitToShell();
- }
-
- // remember the version
-
- if ((versRsrc = (unsigned char **)Get1Resource('vers', 1)) != 0)
- PLstrcpy(gWTVersion, *versRsrc + 6);
-
- // get an event or two...
- (void)GetNextEvent(0, &gTheEvent);
- (void)GetNextEvent(0, &gTheEvent);
-
- // Install our standard AppleEvent handlers
- // Careful! My MPW PPCC and Metrowerks appear to be using different headers.
-
- #ifndef NewAEEventHandlerProc
- # ifdef NewEventHandlerProc
- # define NewAEEventHandlerProc NewEventHandlerProc
- # else
- # define NewAEEventHandlerProc(proc) (EventHandlerProcPtr)proc
- # endif
- #endif
-
- err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, NewAEEventHandlerProc(AEQuitApp), kAEQuitApplication, false);
- if (err == noErr)
- err = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, NewAEEventHandlerProc(AEOpenDocs), kAEOpenDocuments, false);
- if (err == noErr)
- err = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, NewAEEventHandlerProc(AEPrintDocs), kAEPrintDocuments, false);
- if (err == noErr)
- err = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, NewAEEventHandlerProc(AEOpenApp), kAEOpenApplication, false);
-
- FailOSErr(err);
-
- InitDirScrnWrite();
-
- PLstrcpy(titleStr, (StringPtr)"\pling2.world");
- strcpy((char *)gWorldFileName, ":wt:worlds:ling2.world");
-
- // starting up with shift key down ==> allow the user to use a different world file!
-
- if (gTheEvent.modifiers & shiftKey) {
- SFTypeList sfList = {'TEXT'};
- Str255 worldName;
-
- StandardGetFile(nil, 1, sfList, &sfReply);
-
- if (sfReply.sfGood) {
- PathNameFromDirID(sfReply.sfFile.vRefNum, sfReply.sfFile.parID, worldName);
- PLstrcpy(titleStr, sfReply.sfFile.name);
- PLstrcat(worldName, sfReply.sfFile.name);
- strcpy(gWorldFileName, p2cstr(worldName));
- }
- }
-
- /* Open window... */
- gMainWindow = GetNewCWindow(rWindowID, nil, (WindowPtr)-1);
- FailNil(gMainWindow);
-
- SetPort(gMainWindow);
- TextFont(monaco);
- TextSize(12);
- TextMode(srcCopy);
- SizeWindow(gMainWindow, SCREEN_WIDTH, SCREEN_HEIGHT + kBottomBorder, false);
- SetWTitle(gMainWindow, titleStr);
-
- ShowWindow(gMainWindow);
-
- // Kludge the zoomRects so we toggle between "micro" and "normal" sizes.
-
- wHndl = (WStateData **)((WindowPeek)gMainWindow)->dataHandle;
- (*wHndl)->stdState.top = (*wHndl)->userState.top;
- (*wHndl)->stdState.left = (*wHndl)->userState.left;
- (*wHndl)->stdState.bottom = (*wHndl)->stdState.top + (SCREEN_HEIGHT<<1) + kBottomBorder;
- (*wHndl)->stdState.right = (*wHndl)->stdState.left + (SCREEN_WIDTH<<1);
-
- gWTFTWindow = gMainWindow;
- InitDirScrnGraphicsWindow(gMainWindow, initPal);
- }
-
-
- /**/
-
-
- void TogglePause(void)
- {
- Str255 aStr;
-
- if (gGameOn) {
- gPaused = !gPaused;
-
- GetIndString(aStr, rUtilityStrs, (gPaused) ? rStrContinue : rStrPause);
- SetItem(gFileMenu, rFilePause, aStr);
- }
- }
-
-
- /**/
-
-
- static void doMenu(long mResult)
- {
- int theMenu, theItem;
- Str255 daName;
- char compilerStr[64], dateTimeStr[64];
- GrafPtr savePort;
-
- theItem = LoWord(mResult);
- theMenu = HiWord(mResult);
-
- switch (theMenu) {
-
- case rAppleMenuID:
- if (theItem == rAppleAbout) {
- GetIndString(daName, rUtilityStrs, CheckDirScrnWriteFor(gMainWindow) ? rDirWrite : rNoDirWrite);
-
- #if applec
- #define idStr "MPW C"
- #elif __MWERKS__
- #define idStr "Metrowerks"
- #elif THINK_C || THINK_CPLUS
- #define idStr "THINK C"
- #elif __powerc
- #define idStr "PPCC"
- #endif
- strcpy(dateTimeStr, __DATE__);
- strcat(dateTimeStr, ", ");
- strcat(dateTimeStr, __TIME__);
- strcpy(compilerStr, "Compiler: ");
- strcat(compilerStr, idStr);
- strcat(compilerStr,
- #if __powerc
- " PowerPC");
- #else
- " 68K");
- #endif
-
- ParamText(gWTVersion, daName, c2pstr(compilerStr), c2pstr(dateTimeStr));
- Alert(rAboutAlert, nil);
-
- #undef idStr
-
- }
- else {
- GetItem(gAppleMenu, theItem, daName);
- GetPort(&savePort);
- (void) OpenDeskAcc(daName);
- SetPort(savePort);
- }
- break;
-
- case rFileMenuID:
- switch (theItem) {
- case rFileNewGame:
- BeginGame();
- break;
-
- case rFileUseQD:
- gUseQuickDraw = !gUseQuickDraw;
- SetItemMark(gFileMenu, theItem, (gUseQuickDraw) ? checkMark : noMark);
- break;
-
- case rFilePause:
- TogglePause();
- break;
-
- case rFileShowFPS:
- gShowFPS = !gShowFPS;
- SetItemMark(gFileMenu, rFileShowFPS, (gShowFPS) ? checkMark : noMark);
- break;
-
- case rFileQuit:
- gDone = gGameOn = true;
- break;
- }
- break;
-
- case rEditMenuID:
- if (!SystemEdit(theItem-1))
- SysBeep(0);
- break;
-
- default:
- break;
- }
- HiliteMenu(0);
- }
-
-
- /**/
-
-
- static void FixupMenus(void)
- {
- if (gGameOn) {
- DisableItem(gFileMenu, rFileNewGame); // no more new games!
- EnableItem(gFileMenu, rFilePause);
- }
- else
- DisableItem(gFileMenu, rFilePause);
- }
-
-
- /**/
-
-
- int GetAndProcessEvent(void)
- {
- WindowPtr whichWindow;
- long menuResult;
- short partCode;
- int result = gotNoEvent;
- char ch;
-
- if (WaitNextEvent(everyEvent, &gTheEvent, gYieldTime, nil)) {
-
- result = gotOtherEvent;
-
- switch (gTheEvent.what) {
-
- case mouseDown:
-
- switch (partCode = FindWindow(gTheEvent.where, &whichWindow)) {
-
- case inSysWindow:
- SystemClick(&gTheEvent, whichWindow);
- break;
-
- case inMenuBar:
- FixupMenus();
- doMenu(MenuSelect(gTheEvent.where));
- break;
-
- case inDrag:
- SelectWindow(whichWindow);
- DragWindow(whichWindow, gTheEvent.where, &qd.screenBits.bounds);
- break;
-
- case inContent:
- if (whichWindow != FrontWindow())
- SelectWindow(whichWindow);
- break;
-
- case inGoAway:
- if (TrackGoAway(whichWindow, gTheEvent.where)) {
- ExitToShell();
- }
- break;
-
- case inZoomIn:
- case inZoomOut:
- if (TrackBox(whichWindow, gTheEvent.where, partCode)) {
- SetPort(whichWindow);
- EraseRect(&whichWindow->portRect);
- ZoomWindow(whichWindow, partCode, whichWindow == FrontWindow());
- InvalRect(&whichWindow->portRect);
- }
- break;
-
- default:
- break;
-
- } // switch (FindWindow)
- break;
-
-
- case keyDown:
- ObscureCursor();
- // FALL THRU
-
- case autoKey:
- ch = gTheEvent.message; // automagic "& charCodeMask" :)
- if (gTheEvent.modifiers & cmdKey) {
- FixupMenus();
- menuResult = MenuKey(ch);
- if (menuResult & 0xFFFF0000) {
- doMenu(menuResult);
- break; // out of this switch if it was a menu command
- }
- }
- else
- if (ch == kTab || ch == kEsc) // tab/esc ==> pause game
- TogglePause();
-
- // FALL THRU
-
- case keyUp: // if we ever switch these on...
- result = gotKeyEvent;
- break;
-
-
- case updateEvt:
- whichWindow = (WindowPtr)gTheEvent.message;
- BeginUpdate(whichWindow);
-
- if (whichWindow == gMainWindow)
- RefreshWTWindow();
-
- EndUpdate(whichWindow);
- break;
-
- case diskEvt:
- break;
-
- case activateEvt:
- break;
-
- case app4Evt:
- if ((gTheEvent.message << 31) == 0) { // suspend event
- if (!gPaused)
- TogglePause();
- gYieldTime = 60*60;
- gInBackground = true;
- }
- else {
- gYieldTime = 0;
- gInBackground = false;
- SetPort(gMainWindow);
- }
- break;
-
- case kHighLevelEvent:
- AEProcessAppleEvent(&gTheEvent);
- break;
-
- default:
- break;
- } // switch (gTheEvent.what)
- }
-
- return result;
- }
-
-
- /**/
-
-
- void main(void)
- {
- char *myArgs[3];
-
- extern int WTMain(int argc, char **argv);
-
- // chocks away...
-
- init();
-
- myArgs[0] = "wtft";
-
- myArgs[1] = (char *)gWorldFileName;
- myArgs[2] = 0;
-
- while (GetAndProcessEvent())
- ;
-
- WTMain(2, myArgs);
- }
-